Gavin Wood: XCM:跨共识消息格式
The following article is from PolkaWorld Author Gavin Wood
随着最终的 Polkadot 1.0 版本和平行链的临近,交叉共识消息格式(简称 XCM)正在接近其第一个生产就绪版本。这是对可用于实现典型跨链任务的格式、目标、工作方式的介绍。
XCM 是“交叉共识”消息格式,而不仅仅是“跨链”。这种差异是该格式的目标,该格式旨在传达不仅在链之间,而且可以在智能合约和 Pallets 之间,以及通过网桥和分片部分(如 Polkadot 的 Spree)发送的各种信息。
一种格式,而非协议
为了更好地理解 XCM,重要的是要了解它的边界以及它在 Polkadot 技术堆栈中的位置。XCM 是一种消息格式,而不是消息传递协议。它不能用于在系统之间实际“发送”任何消息;它的效用仅在于表达接收者应该做什么。
不包括网桥和合约 Pallet,Polkadot 带有三个不同的系统,用于在其组成链之间对 XCM 消息进行实际通讯:UMP、DMP 和 XCMP。UMP(向上消息传递)允许平行链向它们的中继链发送消息。DMP(向下消息传递)允许中继链将消息向下传递到其平行链之一。XCMP 可能是其中最著名的,允许平行链在它们之间发送消息。
除了在链之间发送消息之外,XCM 在其他方面也很有用,用于与您事先不了解其交易格式的链进行交易。对于业务逻辑变化很小的链(例如比特币),交易格式 —— 或者钱包用来向链发送指令的格式 —— 往往会无限期地保持相同的状态,或者至少是兼容的。使用高度可进化的基于元协议的链,例如 Polkadot 及其组成的平行链,业务逻辑可以通过单个事务跨网络升级。这可以改变任何事情,包括交易格式,给钱包维护者带来潜在的问题,特别是对于需要离线保存的钱包(例如 Parity Signer)。由于 XCM 版本良好、抽象且通用,因此它可以用作一种为钱包提供持久交易格式的手段,用于创建许多常见交易。
目标
XCM 旨在成为共识系统之间交流思想的语言。它需要很强的通用性质,以便在不断发展的生态系统中发挥作用;同时也应该是可扩展的。由于可扩展性不可避免地意味着变化,也应该有很强的兼容性。最后,应该足够高效以在链上运行,并且可在计量环境中运行。
像所有语言一样,有些人会比其他人更倾向于使用某些元素。XCM 的设计方式并不是让每个支持 XCM 的系统都能够解释 XCM 消息。有些消息在某些系统下不会有合理的解释。其他的可能是合理的,但由于资源限制或因为可以以更清晰、更规范的方式表达相同的内容,解释器仍然故意不支持。资源严重受限的系统(如智能合约)可能只支持非常有限的“方言”。
这种普遍性甚至延伸到诸如为执行 XCM 消息支付费用之类的概念。由于我们知道 XCM 可用于多种系统,包括 Gas 计量的智能合约平台和社区平行链,一直到系统平行链与其中继链之间的可信交互,因此我们不想将费用支付等元素作为考虑重点。
为什么不直接
使用原生消息格式
在某些情况下,格式链或智能联系人的本地消息/交易格式可能会被需要,但确实有一些很大的缺点,使其对 XCM 的目标实现显得无用。首先,链之间缺乏兼容性,因此打算向多个目的地发送消息的系统需要了解如何为每个目的地编写消息。在这一点上,即使是单个目的地也可能随着时间的推移改变其本地事务/消息格式。智能合约可能会升级,区块链可能会引入新功能或改变现有功能,从而改变其交易格式。
其次,链上的常见用例不太适合单个交易;可能需要特殊的技巧来提取资金或交换资金,然后将结果全部存入单个交易中。连贯的储备资产框架所需的后续转移通知并不存在于其他人的链中。
第三,诸如支付费用之类的操作不容易适应假设已经像智能合约消息一样协商费用支付的模型。相比之下,交易信封提供了一些支付处理的功能,但通常也被设计为包含一个签名,这在共识系统之间进行通信时没有意义。
如何保护自己免受众贷诈骗
不幸的是,诈骗在区块链领域是一个真正的威胁,需要大家保持警惕。对于骗子来说,虚假的众贷活动可能是一个有吸引力的目标。希望大家始终保持警惕,以保护您自己和不可退还的加密资产。如果你怀疑自己被骗了,请给 Web3 基金会支持团队发邮件。mailto:support@web3.foundation
一些基本的经验法则:
不要分享你的助记词或帐户密码。
记住,骗子很容易在网上冒充别人。
如果你正在 Kusama 上参与一个本地的 crowdloan(见下面的 FAQ),永远不要把你的 KSM 发送到一个地址。本地 crowdloan 是通过 Kusama 的一项特殊交易,使用所谓的活动索引(campaign index)进行交易,在租期结束前,你贡献的 KSM 将保持锁定。靠谱的团队不会要求你发送 KSM 到一个地址来参加 Kusama-native crowdloan。(不用担心,PolkaWorld 会第一时间发布 Kusama 本地 crowdloan 的教程)
如果参与一个非本地的 crowdloan 活动,请随时咨询平行链团队的官方渠道,核实如何参与的细节。请记住,骗子可能会试图冒充官方渠道和团队成员。永远不要参与你不信任的众贷,永远不要向你不信任的人发送代币。
记住,如果你被骗了,没有什么方法可以追回你的资金。
一些初始用
虽然 XCM 的目标是通用的、灵活的和面向未来的,但它当然必须满足实际需求,尤其是链之间的通证转移。可选的费用支付是另一种方式,就像进行交换服务的通用接口一样,在整个 DeFi 世界中都很常见。最后,应该可以使用 XCM 语言进行一些特定的操作;例如,在 Substrate 链中,可能需要将远程调用分派到它的一个 Pallets 中以访问 Niche 功能。
最重要的是,有许多我们希望支持的通证转移模型:我们可能只想简单地控制远程链上的帐户,允许本地链在远程链上拥有一个地址以接收资金并最终将其控制的资金转移到该远程链上的其他账户中。
我们可能有两个共识系统,它们都是特定通证的原生地。想象一下像 USDT 或 USDC 这样的通证,它在几个不同的链上都有可以互换的例子。那么应该也可以在一条链上销毁这样的通证,并在另一条支持的链上铸造相应的通证。在 XCM 的说法中,我们之所以称之为传送,是因为资产的明显移动实际上是通过在一侧销毁它并在另一侧创建克隆来实现的。
最后,可能有两条链想要指定第三条链,其中一条链上的资产可能被视为本地资产,用作该资产的储备。每个链上资产的衍生形式都将得到支持,允许衍生资产交换为支持它的储备链上的基础资产。这可能是两条链不一定相互信任的情况,(至少就相关资产而言)但是愿意信任资产的本地链。这里的一个例子是我们有几个社区平行链想要在彼此之间发送 DOT,它们每个都有一个本地形式的 DOT,由 Statemint 链(DOT 的本地中心)上的平行链控制的 DOT 完全支持。当在链之间发送本地形式的 DOT 时,在后台,“真正的”DOT 会在 Statemint 上的平行链帐户之间移动。
■XCM 剖析
XCM 格式的核心是 XCVM。与某些人的看法相反,这不是有效的罗马数字。事实上,这代表交叉共识虚拟机。这是一台超高级别的非图灵完备计算机,其指令设计为与事务大致处于同一级别。
对于众贷,从贡献开始到租期结束,贡献的 KSM 会被锁定,除非众贷活动未能成功通过拍卖获得插槽使用权,在这种情况下,贡献的 KSM 可以在竞选活动结束的时候解锁,并且由平行链团队退还。在众贷活动从系统中完全删除之前,必须退还所有筹款。
XCM 中的“消息”实际上只是一个运行在 XCVM 上的程序。它是一个或多个 XCM 指令。程序会一直执行,直到它运行到最后或遇到错误为止。
XCVM 包括许多寄存器,以及访问托管它的共识系统的整体状态。指令可能会改变一个寄存器,它们可能会改变共识系统的状态,或者两者兼而有之。
此类指令的一个示例是 TransferAsset,它用于将资产转移到远程系统上的某个其他地址。需要告知要转让哪些资产以及资产要转让给谁或是转让地址。在 Rust 中,是这样声明的:
enum Instruction { TransferAsset
{
assets: MultiAssets,
beneficiary: MultiLocation,
}
/* snip */
}
正如您可能猜到的那样,资产是表示要转让哪些资产的参数,而受益人则说明将这些资产转交给谁。当然,我们还缺少另一条信息,即资产将从何处获取。这是从原发地登记册自动推断出来的。当程序开始时,这个寄存器通常是根据传输系统(网桥、XCMP 或其他)设置的,以反映消息的实际来源,并且它与受益人的信息类型相同。 Origin Register 作为受保护的寄存器运行 —— 程序不能任意对其进行设置,尽管有两条指令可以用来以某种方式改变它。
所使用的类型是 XCM 中非常基本的想法:资产,由 MultiAsset 表示,在共识范围内的位置,由 MultiLocation 表示。 Origin Register 是一个可选的多点位置。
■XCM 中的位置
MultiLocation 类型标识存在于共识世界中的任何单个位置。这是一个相当抽象的想法,可以代表共识中存在的所有事物,从可扩展的多分片区块链(如 Polkadot)一直到平行链上的低级 ERC-20 资产账户。在计算机科学术语中,它实际上只是一个全局单例数据结构,无论其大小或复杂性如何
MultiLocation 始终表示相对于当前位置的位置。你可以把它想象成一个文件系统路径,但是没有办法直接表达文件系统树的“根”。这有一个简单的原因:在 Polkadot 的世界中,区块链可以合并到其他区块链中,也可以从其他区块链中分离出来。区块链可以非常独立地开始发展,并最终被提升为更大共识中的平行链。如果这样做,那么“root”的含义将在一夜之间改变,这可能会给 XCM 消息和其他任何使用 MultiLocation 的消息带来混乱。为了降低风险,我们完全排除了这种可能性。
XCM 中的位置是分层的;Polkadot 的平行链完全存在于整个 Polkadot 共识中,我们称之为内部位置。更严格地说,只要有一个共识系统发生变化,都意味着另一个共识系统的变化,那么前一个系统是后者的内部构造。例如,Canvas 智能合约位于托管它的合约 Pallet 内部。比特币中的 UTXO 是比特币区块链的内部构造。
这意味着 XCM 没有区分“谁”和“在哪里?”的两个问题。从像 XCM 这样相当抽象的东西的角度来看,区别并不重要 —— 两者可以模糊并成为本质上相同的东西。
举例说明:
../Parachain(1000):在平行链内进行评估,将识别我们索引为 1000 的平行链。(在 Rust 中,我们会写作:ParentThen(Parachain(1000)).into()。)
../AccountId32(0x1234...cdef):在平行链中进行评估,将识别中继链上的 32 字节帐户 0x1234...cdef。
Parachain(42)/AccountKey20(0x1234...abcd):在中继链上进行评估,将识别平行链编号 42 上的 20 字节帐户 0x1234...abcd(大概类似于承载以太坊兼容帐户的 Moonbeam)。
XCM 中的资产
在 XCM 中工作时,通常需要引用某种资产。这是因为几乎所有现有的公共区块链都依赖于一些原生数字资产来为其内部经济和安全机制提供支持。对于比特币等工作量证明区块链,原生资产(BTC)用于奖励开发区块链的矿工并防止双重支出。对于 Polkadot 等权益证明区块链,原生资产 (DOT) 会用作一种抵押形式,网络管理员(权益人)必须承担风险才能生成有效区块并获得实物奖励。
一些区块链管理多种资产,例如以太坊的 ERC-20 框架允许在链上管理许多不同的资产。Crypto-kitties 是 NFT 的早期示例。
XCM 旨在能够毫不费力地处理所有此类资产。包括数据类型 MultiAsset 及其关联类型 MultiAssets、WildMultiAsset 和 MultiAssetFilter。让我们看看 Rust 中的 MultiAsset:
structMultiAsset {
id: AssetId,
fun: Fungibility,
}
两个字段定义了我们的资产:id 和 fun,这很好地表明了 XCM 如何处理资产。首先,必须提供整体资产身份。对于可替代资产,这只是标识资产。对于 NFT,这标识了整个资产“类别”。
enumAssetId {
Concrete(MultiLocation),
Abstract(BinaryBlob),
}
资产身份以两种方式之一表示:具体或抽象。抽象机制并没有真正使用,但它允许通过名称指定资产 ID。这很方便,但依赖于接收者以发送者期望的方式解释名称,这可能并不总是那么容易。具体机制是一般用途,使用位置来明确标识资产。对于原生资产(例如 DOT),资产往往被识别为铸造资产的链(在这种情况下是 Polkadot 中继链)。主要在链内管理的资产可以通过其索引的位置来识别。例如,Karura 平行链可能指的是 Statemine 平行链上的资产,位置为 ../Parachain(1000)/PalletInstance(50)/GeneralIndex(42)。
我们有时会使用其他三种相关类型,MultiAssets 就是其中之一,实际上只是意味着一组 MultiAsset 项目。然后我们有 WildMultiAsset;这是一个通配符,可用于匹配一个或多个 MultiAsset 项目。它实际上只支持两种通配符:All(匹配所有资产)和 AllOf 匹配特定身份 (AssetId) 和可替代性的所有资产。值得注意的是,对于后者,不需要指定数量(在可替代的情况下)或实例(对于非可替代的)。
最后,还有 MultiAssetFilter。这最常用,实际上只是 MultiAssets 和 WildMultiAsset 的组合,允许指定通配符或明确(即非通配符)资产列表。
在 Rust XCM API 中,我们提供了很多转换,以尽可能轻松地处理这些数据类型。例如,当我们在 Polkadot 中继链上时,要指定 100 个不可分割的 DOT 资产单位的可替代 MultiAsset,我们将使用 (Here,100).into( )。
持有登记册
让我们看看另一个 XCM 指令:WithdrawAsset。从表面上看,这有点像 TransferAsset 的前半部分:它从原生账户中提取了一些资产。如果他们没有在任何地方存入,那么这肯定是一个非常无用的操作。如果我们查看它的 Rust 声明,我们会发现更多有关其用法的线索:
WithdrawAsset(MultiAssets),
所以,这次只有一个参数(MultiAssets 类型,它规定哪些资产必须从 Origin Register 的所有权中撤出)。但是没有指定放置资产的位置。
这些暂时持有的未动用资产称为持有登记册。(“Holding”是因为它们处于一个不能无限期持续的临时位置,“Register”是因为它有点像 CPU 寄存器,是一个工作数据的地方。)有许多指令可以对保持寄存器进行操作。一个非常简单的指令是 DepositAsset 指令:
enum Instruction {
DepositAsset{
assets: MultiAssetFilter,
max_assets:u32,
beneficiary: MultiLocation,
},
/* snip */
}
有人会发现这看起来很像 TransferAsset 指令中缺失的一半。我们有资产参数,它指定哪些资产应该从持有登记册中删除以存放在链上。max_assets 让 XCM 作者通知接收者打算存入资产的数量。(这种方式在知道持有登记册的内容之前来计算费用时很有帮助,因为存入资产可能是一项成本高昂的操作。)最后是受益人,这与我们之前在 TransferAsset 操作中遇到的参数相同。
有许多指令表示要在持有登记簿上执行的操作,而 DepositAsset 是最简单的指令之一,其他一些则更复杂。
用 XCM 支付费用
XCM 中的费用支付是一个相当重要的用例。Polkadot 社区中的大多数平行链将要求他们的对话者为他们希望进行的任何操作付费,以免他们对“交易垃圾邮件”和拒绝服务攻击持开放态度。对于一般情况,费用是确保 XCM 消息及其传输协议不会被过度使用的好方法。我们来看看 XCM 消息到达 Polkadot 时如何支付费用。
与以太坊交易模型不同,费用支付不是协议中不需要的东西。就像 Rust 的零成本抽象机制一样,费用支付在 XCM 中没有很大的设计开销。
对于确实需要支付一定费用的系统,XCM 提供了使用资产购买执行资源的能力。从广义上讲,包括三个部分:
首先,需要提供一些资产
其次,必须用计算时间交换资产
最后,XCM 操作将按照指示执行
第一部分由提供资产的多个 XCM 指令之一管理。持有登记册中的所得资产将用于支付与执行 XCM 相关的费用。任何未用于支付费用的资产我们将存入某个目的地账户。在我们的示例中,我们假设 XCM 发生在 Polkadot 中继链上,并且它用于 1 个 DOT(即 10,000,000,000 个不可分割的单位)。
到目前为止,我们的 XCM 指令会像如下显示:
WithdrawAsset((Here, 10_000_000_000).into()),
这将我们带到了第二部分,交换这些资产以换取计算时间来支付我们的 XCM。为此,我们有 XCM 指令 BuyExecution:
enum Instruction {
/* snip */
BuyExecution{
fees: MultiAsset,
weight:u64,
},
}
第一项费用应从持有登记册中提取并用于支付费用的金额。从技术上讲,这是最大值,因为任何未使用的余额都会立即退还。
最终花费的金额由解释系统决定 —— 费用仅对其进行限制,如果解释系统需要为所需的执行支付更多费用,则 BuyExecution 指令将导致错误。第二项指定要购买的执行时间量一般不应小于 XCM 程序的总重量。
在我们的示例中,我们将假设所有 XCM 指令的权重为 100 万,因此到目前为止,我们的两个项目(WithdrawAsset 和 BuyExecution)为 200 万。我们将只使用我们必须支付这些费用的 DOT(如果我们相信目的地链没有过多的费用)。到目前为止,让我们看看我们的 XCM:
WithdrawAsset((Here, 10_000_000_000).into()),
BuyExecution {
fees: (Here, 10_000_000_000).into(),
weight: 3_000_000,
},
我们 XCM 的第三部分是存入控股登记册中剩余的资金。为此,我们将只使用 DepositAsset 指令。我们实际上并不知道持有登记册中还剩下多少,但这并不重要,因为我们可以为应该存入的资产指定一个通配符。我们会将它们放在 Statemint 的主权账户中(标识为 Parachain(1000))。
因此,我们最终的 XCM 指令如下所示:
WithdrawAsset((Here, 10_000_000_000).into()),
BuyExecution {
fees: (Here, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: Parachain(1000).into(),
},
通过 XCM 在链之间移动资产
将资产发送到另一个链可能是链间消息传递的最常见用例。允许一条链管理另一条链的本地资产并允许各种衍生用例也是常见的,最简单的是去中心化交易所,但通常归为去中心化金融或 DeFi。
一般来说,资产在链之间移动有两种方式,这取决于链之间是否信任彼此的安全性和逻辑。
传送
对于相互信任的链(在相同的整体共识和安全机制下的同质分片),我们可以使用 Polkadot 作为传送的框架,这基本上意味着发送方销毁资产并在接收方铸造。这样既简单又高效 —— 只需要两条链的协调,并且只涉及任一侧的动作。
让我们看看 XCM 将(大部分)1 个 DOT 从 Polkadot 中继链传送到它在 Statemint 上的主权帐户时的样子。我们假设 Polkadot 方面已经支付了费用。
WithdrawAsset((Here, 10_000_000_000).into()),
InitiateTeleport {
assets: All.into(),
dest: Parachain(1000).into(),
xcm: Xcm(vec![
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: Parent.into(),
},
]),
}
如您所见,这看起来与直接提款-买-存模式非常相似。不同之处在于在最后两条指令(BuyExecution 和 DepositAsset)周围插入的 InitiateTeleport 指令。发送方(Polkadot 中继链)在执行 InitiateTeleport 指令时正在创建一条全新的消息;它将 xcm 字段放入一个新的 XCM ReceiveTeleportedAsset 中,然后将此 XCM 发送到接收器 (Statemint) 。Statemint 相信 Polkadot 中继链在发送消息之前已经销毁了其一侧的 1 个 DOT。
受益人被声明为 Parent.into(),有的读者可能想知道这在 Polkadot 中继链指的是什么。答案是“nothing”。xcm 参数中的所有内容都是从接收方的角度编写的,尽管这是注入 Polkadot 中继链整个 XCM 的一部分,但它实际上仅在 Statemint 上执行。
当 Statemint 最终收到消息时,它看起来像这样:
ReceiveTeleportedAsset((Parent, 10_000_000_000).into()),
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: Parent.into(),
},
您可能会注意到,这看起来与之前的 WithdrawAsset XCM 非常相似。唯一的区别是,它不是通过从本地账户提款来为费用和存款提供资金,而是通过相信 DOT 在发送方(Polkadot 中继链)上被忠实地销毁并尊重 ReceiveTeleportedAsset 的消息。
值得注意的是,我们在 Polkadot 中继链上发送的 1 个 DOT 的资产标识符(这里指的是中继链本身,即 DOT 的原生地)已自动变异为它在 Statemint 上的表示:Parent.into(),即 Statemint 中继链的位置。
受益人也被指定为 Polkadot 中继链,因此其主权账户(在 Statemint 上)被记入新铸造的 1 DOT。XCM 可能只是轻松地为受益人命名了一个帐户。实际上,可以使用从中继链发送的 TransferAsset 来移动这 1 个 DOT。
储备金
跨链转移资产的替代方式稍微复杂一些。储备金名字来自储备银行,其中资产被“保留”,以使某些已发布的承诺有价值的观点具有可信度。例如,如果我们可以合理地相信在独立的平行链上发行的每个“衍生”DOT 恰好可以兑换 1 个“真实”(例如 Statemint 或中继链)DOT,那么我们可以将平行链的 DOT 视为在经济上等同于真实 DOT 。(大多数银行都做所谓的准备金业务,这意味着他们保留的准备金少于面值。)所以,准备金是存储“真实”资产的地方,出于传输目的,其逻辑和安全性受到发送方和接收方的信任。发送方和接收方的任何相应资产都将是衍生品,但它们将得到 100% 的“真实”储备资产支持。假设平行链表现良好,这将使衍生品 DOT 或多或少与基础储备 DOT 的价值相同。储备资产保存在储备链上的发送者/接收者的主权账户(即由发送者或接收者链控制的账户)中,因此有充分的理由,除非平行链出现问题,否则它们会得到很好的保护。
转移机制则是发送方将指示储备金将发送方拥有的资产(并将其用作同一资产的自身版本的储备)转移到接收方的主权账户。这意味着发送方和接收方不需要信任对方的逻辑或安全性,而只需要信任备用链的逻辑和安全性。这也意味着三方需要协调,增加了整体成本、时间和复杂性。
这次我们将从平行链 2000 发送 1 个 DOT 到平行链 2001,它在平行链 1000 上使用储备支持的 DOT。同样,我们假设费用已经在发送方处被支付。
WithdrawAsset((Parent, 10_000_000_000).into()),
InitiateReserveWithdraw {
assets: All.into(),
dest: ParentThen(Parachain(1000)).into(),
xcm: Xcm(vec![
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositReserveAsset {
assets: All.into(),
max_assets: 1,
dest: ParentThen(Parachain(2001)).into(),
xcm: Xcm(vec![
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: ParentThen(Parachain(2000)).into(),
},
]),
},
]),
},
外部部分处理在发送方(平行链 2000)上提取 1 个 DOT 并撤回 Statemint(平行链 1000)上相应的 1 个 DOT —— 为此使用了 InitiateReserveWithdraw。
WithdrawAsset((Parent, 10_000_000_000).into()),
InitiateReserveWithdraw {
assets: All.into(),
dest: ParentThen(Parachain(1000)).into(),
xcm: /* snip */
}
现在我们在 Statemint 的持有登记册中有 1 个 DOT。在我们做出指令之前,我们需要在 Statemint 上购买一些执行时间:
/*snip*/
xcm: Xcm(vec![
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositReserveAsset {
assets: All.into(),
max_assets: 1,
dest: ParentThen(Parachain(2001)).into(),
xcm: /* snip */
},
]),
/*snip*/
我们使用 1 DOT 来支付费用,假设每个 XCM 操作有 100 万。支付了这一项操作后,我们将 1 DOT 存入平行链 2001 的主权账户,但这样做是作为储备资产,这意味着我们也会要求 Statemint 向该接收链发送 XCM,通知它传输以及要对生成的衍生资产执行的一些指令。DepositReserveAsset 说明并不总是很有意义;为了让它有意义,dest 必须是一个可以合理地在储备链上持有资金的位置,而且也是储备链可以向其发送 XCM 的位置。平行链恰好符合这一要求。
/*snip*/
xcm: Xcm(vec![
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: ParentThen(Parachain(2000)).into(),
},
]),
/*snip*/
最后一部分定义了到达平行链 2001 的部分消息。就像启动传送操作一样,DepositReserveAsset 在这种情况下编写并发送一条新消息 ReserveAssetDeposited。正是这个消息,虽然包含我们定义的 XCM 程序,但到达了接收平行链:
ReserveAssetDeposited((Parent, 10_000_000_000).into()),
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: ParentThen(Parachain(2000)).into(),
},
结论
以上就是本文的内容,希望本篇内容有助于解释 XCM 是什么,以及工作机制的基础知识。在下一篇文章中,我们将更深入地研究 XCVM 的架构、执行模型、错误处理方式、XCM 的版本控制系统以及如何在连接良好的相互依赖的生态系统中管理格式升级;作为其查询 — 响应系统以及 XCM 在 Substrate 中的工作原理。我们还将讨论 XCM 的一些未来发展方向、计划的功能以及发展它的过程。